Imports System.IO
Imports System.Collections

Namespace gtalkNotepad

	Public Class Settings

		''' <summary>
		''' Name of the settings file.
		''' </summary>
		Private Const SETTINGS_FILE_NAME As String = "gtalkNotepad.settings"

		' Keys for the setting file.
		Private Const SETTINGS_KEY_USERNAME As String = "UserName"				' User name used to log into mail/chat
		Private Const SETTINGS_KEY_PASSWORD As String = "Password"				' Password used to log into mail/chat
		Private Const SETTINGS_KEY_CONNECTSERVER As String = "ConnectServer"	' The main chat server?
		Private Const SETTINGS_KEY_SERVER As String = "Server"					' Domain to log into e.g. gmail.com
		Private Const SETTINGS_KEY_PORT As String = "Port"						' Port used to listen for chat or send it?
		Private Const SETTINGS_KEY_USESSL As String = "UseSSL"					' If you want to send chat over ssl
		Private Const SETTINGS_KEY_MAILFEED As String = "MailFeed"				' The path to your gmail atom feed
		Private Const SETTINGS_KEY_RESOURCE As String = "Resource"				' The name of your chat client, this is used to determine what client will handle your chat request.
		Private Const SETTINGS_KEY_ATOMNAMESPACE As String = "AtomNamespace"	' Atom namespace URI
		Private Const SETTINGS_KEY_SELFLABEL As String = "SelfLabel"			' The Me: in the chat window when you type.
		Private Const SETTINGS_KEY_KEEPALIVE As String = "KeepAlive"			' The keep alive interval, 0 to disable keepalive packets.
		Private Const SETTINGS_KEY_VERBOSITY As String = "Verbosity"			' The verbosity level of the application.
		
		' Location of the form on the screen
		Private Const SETTINGS_KEY_LEFT As String = "Left"
		Private Const SETTINGS_KEY_TOP As String = "Top"
		Private Const SETTINGS_KEY_WIDTH As String = "Width"
		Private Const SETTINGS_KEY_HEIGHT As String = "Height"

		' Some default values for the above keys
		Private Const SETTINGS_DEFAULT_CONNECTSERVER As String = "talk.google.com"
		Private Const SETTINGS_DEFAULT_SERVER As String = "gmail.com"
		Private Const SETTINGS_DEFAULT_PORT As Integer = 5222
		Private Const SETTINGS_DEFAULT_USESSL As Boolean = False
		Private Const SETTINGS_DEFAULT_MAILFEED As String = "https://mail.google.com/mail/feed/atom"
		Private Const SETTINGS_DEFAULT_RESOURCE As String = "notepad.v0"
		Private Const SETTINGS_DEFAULT_ATOMNAMESPACE As String = "http://purl.org/atom/ns#"
		Private Const SETTINGS_DEFAULT_SELFLABEL As String = "Me: "
		Private Const SETTINGS_DEFAULT_KEEPALIVE As Integer = 600
		Private Const SETTINGS_DEFAULT_VERBOSITY As Integer = 0
		Private Const SETTINGS_DEFAULT_LEFT As Integer = 0
		Private Const SETTINGS_DEFAULT_TOP As Integer = 0
		Private Const SETTINGS_DEFAULT_WIDTH As Integer = 0
		Private Const SETTINGS_DEFAULT_HEIGHT As Integer = 0

		''' <summary>
		''' Stores the key/value pairs read in from the settings file.
		''' </summary>
		''' <remarks></remarks>
		Private m_hashSettings As New Hashtable()

		''' <summary>
		''' Determines if the login info exists inside the settings file.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>True if a user name and password are both found in the settings file. False otherwise.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property HaveLoginInfo() As Boolean
			Get
				Return (Not String.IsNullOrEmpty(m_hashSettings(SETTINGS_KEY_USERNAME)) AndAlso Not String.IsNullOrEmpty(m_hashSettings(SETTINGS_KEY_PASSWORD)))
			End Get
		End Property

		''' <summary>
		''' Path of the settings file.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>String containing the full path to the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property FileLocation() As String
			Get
				Return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), SETTINGS_FILE_NAME)
			End Get
		End Property

		''' <summary>
		''' User name used to log into mail/chat.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>String value containing the username from the settings file.</returns>
		''' <remarks>The username should not contain the domain e.g. user not user@gmail.com</remarks>
		Public ReadOnly Property UserName() As String
			Get
				Return m_hashSettings(SETTINGS_KEY_USERNAME)
			End Get
		End Property

		''' <summary>
		''' Password used to log into mail/chat
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>String value containing the clear text password from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property Password() As String
			Get
				'TODO: Encrypt the password inside the settings file.
				Return m_hashSettings(SETTINGS_KEY_PASSWORD)
			End Get
		End Property

		''' <summary>
		''' The resource or client being used to chat.
		''' </summary>
		''' <value></value>
		''' <returns>String value containing the resourec from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property Resource() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_RESOURCE) Then
					Return m_hashSettings(SETTINGS_KEY_RESOURCE)
				Else
					Return SETTINGS_DEFAULT_RESOURCE
				End If
			End Get
		End Property

		''' <summary>
		''' URI of the XMPP chat server to use.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>String value containing the URI of the XMPP chat server from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property ConnectServer() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_CONNECTSERVER) Then
					Return m_hashSettings(SETTINGS_KEY_CONNECTSERVER).ToString()
				Else
					Return SETTINGS_DEFAULT_CONNECTSERVER
				End If
			End Get
		End Property

		''' <summary>
		''' Domain of the user logging in.
		''' </summary>
		''' <value></value>
		''' <returns>String value containing the server from the settings file.</returns>
		''' <remarks>Defaults to gmail.com, but can be any other custom domain.</remarks>
		Public ReadOnly Property Server() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_SERVER) Then
					Return m_hashSettings(SETTINGS_KEY_SERVER).ToString()
				Else
					Return SETTINGS_DEFAULT_SERVER
				End If
			End Get
		End Property

		''' <summary>
		''' Port used to connect to the chat server.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>Integer value containing the port number from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property Port() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_PORT) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_PORT).ToString())
				Else
					Return SETTINGS_DEFAULT_PORT
				End If
			End Get
		End Property

		''' <summary>
		''' Use an SSL connection to encrypt chat.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>Boolean form the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property UseSSL() As Boolean
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_USESSL) Then
					Return Convert.ToBoolean(m_hashSettings(SETTINGS_KEY_USESSL).ToString())
				Else
					Return SETTINGS_DEFAULT_USESSL
				End If
			End Get
		End Property

		''' <summary>
		''' URI for the mail atom feed.
		''' </summary>
		''' <value></value>
		''' <returns>String value containing the URI from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property MailFeed() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_MAILFEED) Then
					Return m_hashSettings(SETTINGS_KEY_MAILFEED).ToString()
				Else
					Return SETTINGS_DEFAULT_MAILFEED
				End If
			End Get
		End Property

		Public ReadOnly Property AtomNamespace() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_ATOMNAMESPACE) Then
					Return m_hashSettings(SETTINGS_KEY_ATOMNAMESPACE).ToString()
				Else
					Return SETTINGS_DEFAULT_ATOMNAMESPACE
				End If
			End Get
		End Property

		Public ReadOnly Property SelfLabel() As String
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_SELFLABEL) Then
					Return m_hashSettings(SETTINGS_KEY_SELFLABEL).ToString()
				Else
					Return SETTINGS_DEFAULT_SELFLABEL
				End If
			End Get
		End Property

		''' <summary>
		''' Used to prevent the connection from timing out.
		''' </summary>
		''' <value>Read Only</value>
		''' <returns>Integer value containing the interval (in seconds) from the settings file.</returns>
		''' <remarks></remarks>
		Public ReadOnly Property KeepAlive() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_KEEPALIVE) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_KEEPALIVE).ToString())
				Else
					Return SETTINGS_DEFAULT_KEEPALIVE
				End If
			End Get
		End Property

		''' <summary>
		''' The verbosity level of the application. The higher the value, the more "chatty" the application will be.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public ReadOnly Property Verbosity() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_VERBOSITY) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_VERBOSITY).ToString())
				Else
					Return SETTINGS_DEFAULT_VERBOSITY
				End If
			End Get
		End Property		
		
		Public Property Top() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_TOP) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_TOP).ToString())
				Else
					Return SETTINGS_DEFAULT_TOP
				End If
			End Get
			Set(value as Integer)				
				If m_hashSettings.Contains(SETTINGS_KEY_TOP) Then
					m_hashSettings(SETTINGS_KEY_TOP) = value
				Else
					m_hashSettings.Add(SETTINGS_KEY_TOP, value)
				End If
			End Set
		End Property		
		
		Public Property Left() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_LEFT) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_LEFT).ToString())
				Else
					Return SETTINGS_DEFAULT_LEFT
				End If
			End Get
			Set(value as Integer)				
				If m_hashSettings.Contains(SETTINGS_KEY_LEFT) Then
					m_hashSettings(SETTINGS_KEY_LEFT) = value
				Else
					m_hashSettings.Add(SETTINGS_KEY_LEFT, value)
				End If
			End Set
		End Property		
		
		Public Property Width() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_WIDTH) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_WIDTH).ToString())
				Else
					Return SETTINGS_DEFAULT_WIDTH
				End If
			End Get
			Set(value as Integer)				
				If m_hashSettings.Contains(SETTINGS_KEY_WIDTH) Then
					m_hashSettings(SETTINGS_KEY_WIDTH) = value
				Else
					m_hashSettings.Add(SETTINGS_KEY_WIDTH, value)
				End If
			End Set
		End Property		
		
		Public Property Height() As Integer
			Get
				If m_hashSettings.Contains(SETTINGS_KEY_HEIGHT) Then
					Return Convert.ToInt32(m_hashSettings(SETTINGS_KEY_HEIGHT).ToString())
				Else
					Return SETTINGS_DEFAULT_HEIGHT
				End If
			End Get
			Set(value as Integer)				
				If m_hashSettings.Contains(SETTINGS_KEY_HEIGHT) Then
					m_hashSettings(SETTINGS_KEY_HEIGHT) = value
				Else
					m_hashSettings.Add(SETTINGS_KEY_HEIGHT, value)
				End If
			End Set
		End Property

		''' <summary>
		''' Settings constructor.
		''' </summary>
		''' <remarks></remarks>
		Public Sub New()
			readSettings()
		End Sub

		''' <summary>
		''' Refreshes the values from the settings file.
		''' </summary>
		''' <remarks></remarks>
		Public Sub Refresh()
			readSettings()
		End Sub
		
		Public Sub Save()
			saveSettings()
		End Sub
		
		Private Sub saveSettings()
			Dim fileLines As String()

			If File.Exists(Me.FileLocation) Then
				fileLines = File.ReadAllLines(Me.FileLocation)
				File.Delete(Me.FileLocation)
			End If

			Dim keyValue(1) As String

			Dim swSettings As New StreamWriter(Me.FileLocation)

			If Not fileLines Is Nothing Then
				For Each line As String In fileLines
					keyValue = splitSettings(line)
					If Not String.IsNullOrEmpty(keyValue(0)) Then
						If m_hashSettings.Contains(keyValue(0)) Then
							swSettings.WriteLine(keyValue(0) & ": " & m_hashSettings(keyValue(0)))
							m_hashSettings.Remove(keyValue(0))
						Else
							swSettings.WriteLine(keyValue(0) & ": " & keyValue(1))
						End If
					Else
						swSettings.WriteLine(keyValue(1))
					End If
				Next
			End If

			For Each key As String In m_hashSettings.Keys
				swSettings.WriteLine(key & ": " & m_hashSettings(key))
			Next

			swSettings.Flush()
			swSettings.Close()

		End Sub

		''' <summary>
		''' Private function to read the settings file and populate hashSettings with
		''' the key/value pairs.
		''' </summary>
		''' <remarks></remarks>
		Private Sub readSettings()
			If File.Exists(Me.FileLocation) Then
				'Dim fileSettings As FileStream = File.OpenRead(Me.FileLocation)
				Dim srSettings As New StreamReader(Me.FileLocation)
				Do Until srSettings.EndOfStream
					Dim buffer As String = srSettings.ReadLine()
					Dim keyval As String() = splitSettings(buffer)
					If Not String.IsNullOrEmpty(keyval(0)) Then
						If m_hashSettings.ContainsKey(keyval(0)) Then
							m_hashSettings(keyval(0)) = keyval(1)
						Else
							m_hashSettings.Add(keyval(0), keyval(1))
						End If
					End If
				Loop
				srSettings.Close()
			Else
				Dim settings() As String = {"UserName: ", "Password: ", "Server: "}
				File.WriteAllLines(Me.FileLocation, settings)
			End If
		End Sub

		Private Function splitSettings(ByVal text As String) As String()
			Dim rtn(1) As String
			If Not text.StartsWith("#") And text.Contains(":") Then
				Dim idxColon As Int32 = text.IndexOf(":")
				rtn(0) = text.Substring(0, idxColon).Trim()
				rtn(1) = text.Substring(idxColon + 1).Trim()
			Else
				rtn(1) = text
			End If
			Return rtn
		End Function
	End Class

End Namespace
